package com.ljx.aop.aspect;

import com.alibaba.fastjson.JSON;
import com.ljx.aop.annotation.SystemLog;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * @author 李捷禧
 * Date: 2023/4/20
 * ClassName: LogAspect
 */

@Component
@Aspect
@Slf4j
public class LogAspect {

    //切点
    @Pointcut("@annotation(com.ljx.aop.annotation.SystemLog)")
    public void pt(){

    }

    //通知
    @Around("pt()")
    public Object printLog(ProceedingJoinPoint joinPoint) throws Throwable {

        Object ret;
        try {
            //拦截器，分析目标方法在执行过程的信息
            handleBefore(joinPoint);
            //用来执行目标方法
            //执行完目标方法后的结果
            //proceed方法返回值是目标方法的返回值
           ret = joinPoint.proceed();
           //拦截器，将结果打印出来
            handleAfter(ret);
        } finally {
            // 结束后换行
            log.info("=======End=======" + System.lineSeparator());
        }
        return ret;
    }

    /**
     * 前置通知：在目标方法执行之前进行
     * 作用：分析打印目标方法各种信息
     * @param joinPoint
     */
    private void handleBefore(ProceedingJoinPoint joinPoint) {

        ServletRequestAttributes requestAttributes =
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        //获取请求相关信息
        HttpServletRequest request = requestAttributes.getRequest();
        //获取添加SystemLog方法的相关信息
        SystemLog systemLog = getSystemLog(joinPoint);

        log.info("=======Start=======");
        // 打印请求 URL
        log.info("URL            : {}",request.getRequestURL());
        // 打印描述信息
        log.info("BusinessName   : {}",systemLog.businessName());
        // 打印 Http method
        log.info("HTTP Method    : {}",request.getMethod());
        // 打印调用 controller 的全路径以及执行方法
        log.info("Class Method   : {}.{}",joinPoint.getSignature().getDeclaringTypeName(),
                ((MethodSignature)joinPoint.getSignature()).getName());
        // 打印请求的 IP
        log.info("IP             : {}",request.getRemoteHost());
        // 打印请求入参
        log.info("Request Args   : {}", JSON.toJSONString(joinPoint.getArgs()));
    }

    /**
     *
     * @param joinPoint
     * @return
     */
    private SystemLog getSystemLog(ProceedingJoinPoint joinPoint) {
        //用于获取目标方法的签名信息，即目标方法的名称、参数类型、修饰符等信息
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //目的是判断目标方法是否被标记了 `@SystemLog` 注解
        SystemLog annotation = signature.getMethod().getAnnotation(SystemLog.class);
        return annotation;
    }

    /**
     * 后置通知：是目标方法后执行
     * 作用：打印目标方法返回值
     * @param ret
     */
    private void handleAfter(Object ret) {
        // 打印出参
        log.info("Response       : {}",JSON.toJSONString(ret));
    }

}
